package com.kbtd.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kbtd.dto.LoginFormDTO;
import com.kbtd.dto.Result;
import com.kbtd.dto.UserDTO;
import com.kbtd.entity.User;
import com.kbtd.mapper.UserMapper;
import com.kbtd.service.IEmailService;
import com.kbtd.service.IUserService;
import com.kbtd.utils.RegexUtils;
import com.kbtd.utils.UserHolder;
import com.kbtd.utils.redis.RedisUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.kbtd.constant.RedisConstants.*;
import static com.kbtd.constant.SystemConstants.LOGIN_HEADER;
import static com.kbtd.constant.SystemConstants.PROJECT_NAME;

/**
 * 用户服务实现类
 *
 * @author wp
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IEmailService emailService;

    @Override
    public Result sendCode(String email) {
        //验证手机号格式
        if (RegexUtils.isEmailInvalid(email)) {
            return Result.fail("无效邮箱！");
        }

        //生成验证码
        String code = RandomUtil.randomNumbers(6);

        //保存验证码
        String key = RedisUtils.createKey(LOGIN_CODE_KEY_PREFIX, email);
        stringRedisTemplate.opsForValue().set(key, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);

        //发送验证码
        emailService.sendCode(email, code);
        log.debug("验证码发送成功：" + code);

        //返回
        return Result.ok();
    }

    @Override
    public Result login(LoginFormDTO loginForm) {

        //判断用户是否已经登录
        if(!ObjectUtils.isEmpty(UserHolder.getUser())) {
            return Result.fail("账号已登录，请勿重复登录");
        }

        User user = null;

        String email = loginForm.getEmail();
        String password = loginForm.getPassword();
        String userCode = loginForm.getCode();

        //验证手机号格式
        if (RegexUtils.isEmailInvalid(email)) {
            return Result.fail("无效邮箱！");
        }
        
        //验证密码或验证码
        //验证密码
        if (!StringUtils.isEmpty(password)) {
            //数据库校验用户名密码
            user = query().eq("password", password)
                    .eq("email", email)
                    .one();

            if (ObjectUtils.isEmpty(user)) {
                //校验失败
                return Result.fail("用户名或密码错误");
            }
        } else if (!StringUtils.isEmpty(userCode)) {
            //验证验证码
            //取验证码缓存
            String codeKey = RedisUtils.createKey(LOGIN_CODE_KEY_PREFIX, email);
            String code = stringRedisTemplate.opsForValue().get(codeKey);

            if (userCode.equals(code)) {
                //验证码校验成功，查询数据库
                user = query().eq("email", email)
                        .one();

                if (ObjectUtils.isEmpty(user)) {
                    //将用户添加到数据库
                    user = new User();
                    user.setEmail(email);
                    save(user);
                }
            } else {
                return Result.fail("验证码错误");
            }
        } else {
            return Result.fail("密码或验证码为空！");
        }
        //登陆成功，生成token
        UUID token = UUID.randomUUID();
        //将token存入redis
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user, userDTO);
        String tokenKey = RedisUtils.createKey(LOGIN_USER_KEY_PREFIX, token.toString());
        Map<String, Object> map = BeanUtil.beanToMap(userDTO);
        Map<String, String> userMap = MapUtil.map
                (map, (key, value) -> value == null ? null : value.toString());

        stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);
        stringRedisTemplate.expire(tokenKey, LOGIN_USER_TTL, TimeUnit.MINUTES);

        return Result.ok(token);
    }

    @Override
    public Result logout(HttpServletRequest request) {
        UserDTO user = UserHolder.getUser();
        if (ObjectUtils.isEmpty(user)) {
            return Result.fail("账号未登录");
        }
        String token = request.getHeader(LOGIN_HEADER);
        String key = RedisUtils.createKey(LOGIN_USER_KEY_PREFIX, token);
        log.debug("删除缓存key:" + key);
        stringRedisTemplate.delete(key);
        return Result.ok();
    }

    @Override
    public Result sign() {
        //1. 获取当前用户
        Long userId = UserHolder.getUser().getId();
        //2. 获取日期
        LocalDateTime now = LocalDateTime.now();
        //3. 拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = RedisUtils.createKey(USER_SIGN_KEY_PREFIX, userId + keySuffix);
        //4. 获取今天是当月第几天(1~31)
        int dayOfMonth = now.getDayOfMonth();
        //5. 写入Redis  BITSET key offset 1
        stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
        return Result.ok();
    }

    @Override
    public Result signCount() {
        //1. 获取当前用户
        Long userId = UserHolder.getUser().getId();
        //2. 获取日期
        LocalDateTime now = LocalDateTime.now();
        //3. 拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern(":yyyyMM"));
        String key = RedisUtils.createKey(USER_SIGN_KEY_PREFIX, userId + keySuffix);

        Long count = stringRedisTemplate.execute(connection -> connection.bitCount(key.getBytes()), true);
        return Result.ok(count);
    }
}
